home *** CD-ROM | disk | FTP | other *** search
/ Software of the Month Club 1998 May / Software of the Month Club 1998 May.iso / pc / dos / child / poetry / main.c < prev    next >
C/C++ Source or Header  |  1998-03-03  |  24KB  |  994 lines

  1. /************* Random poetry generator ***********************/
  2. /**                                                         **/
  3. /**                           poetry.c                      **/
  4. /**                                                         **/
  5. /** Copyright (C) Paul Gaze 1997                            **/
  6. /**     Please, notify me, if you make any                  **/
  7. /**     changes to this file.                               **/
  8. /*************************************************************/
  9. #include    <stdio.h>
  10. #include    <stdlib.h>
  11. #include    <string.h>
  12. #include    <time.h>
  13.  
  14. #define    DEBUG_MESSAGES    0
  15.  
  16. //**************************************
  17. //    Structures
  18. //**************************************
  19. typedef struct{
  20.     char    *String;
  21.     int        Subject,Object;
  22. }VERB;
  23.  
  24. #define    MAX_LINE_LENGTH    256
  25.  
  26. #define    GENDA_HE    0
  27. #define    GENDA_SHE    1
  28. #define    GENDA_IT    2
  29. #define    GENDA_THEY    3
  30. #define    GENDA_I        4
  31. #define    GENDA_WE    5
  32.  
  33. typedef struct{
  34.     void    *Next;
  35.     char    *String;
  36. }TYPE_DATA;
  37.  
  38. typedef struct{
  39.     char    *String;
  40.     int        Genda;
  41.     int        NTypes;
  42.     int        *Types;
  43. }NOUN;
  44.  
  45. typedef struct{
  46.     int        NQuality;
  47.     NOUN    *Quality;
  48.     char    *String;
  49. }TYPE;
  50.  
  51. typedef struct{
  52.     int        NVerb;
  53.     VERB    *Verb;
  54.     int        NNoun;
  55.     NOUN    *Noun;
  56.     int        NExclamation;
  57.     char    **Exclamation;
  58.     int        NType;
  59.     TYPE    *Type;
  60. }POET;
  61.  
  62. typedef struct{
  63.     int        N;
  64.     NOUN     *Noun;
  65.     NOUN    *Quality;
  66.     char    *String;
  67.     int        Genda;
  68.     int        HisGenda;
  69.     int        NTypes;
  70.     int        *Types;
  71. }THING;
  72.  
  73. typedef struct{
  74.     void    *Next;
  75.     void    *Data;
  76.     size_t    Amount;
  77. }MEMBLOCK;
  78.  
  79. //**************************************
  80. //    Prototypes
  81. //**************************************
  82. POET    *LoadPoet(char *name);
  83. void    ErrorExit(char *message);
  84. void    ComposePoem(char *output, POET *poet, int seed);
  85. int        RND(int range);
  86. void    SetGenda(THING *t);
  87. void    NewThing(POET *p, THING *t);
  88. void    ChooseQuality(POET *p, THING *t);
  89. void    Replace(char *key, char *replacement, char *str);
  90. int        FindLine(char **lines, int nlines, char *str);
  91. void    *GetMem(size_t amount, char *ErrorMessage);
  92. char    *CloneString(char *from);
  93. void    FreeMem(void *data);
  94. void    ReadNoun(char *from, NOUN *noun, POET *p);
  95. void    IndentLine(char *line);
  96. int        StringToBin(char *str);
  97. void    ShowHelp(void);
  98. #define    FAIL(message)    {printf(message); goto fail;}
  99.  
  100. //**************************************
  101. //    Static data
  102. //**************************************
  103. char    *He[]={"he","she","it","they","i","we"};
  104. char    *Him[]={"him","her","it","them","me","us"};
  105. char    *His[]={"his","her","its","their","my","our"};
  106. char    *Himself[]={"himself","herself","itself","themselves","myself","ourselves"};
  107.  
  108. //    Constants
  109. int            NumberLines=6,PrintWidth=60;
  110. char        *SubStr,*ObjStr;
  111. MEMBLOCK    *MemList=0;
  112. size_t        TotalMemory=0;
  113.  
  114. int main(int argc, char *argv[])
  115. {
  116.     POET    *poet;
  117.     int        j;
  118.     char    input;
  119.     char    *poem,*ss;    
  120.     int        seed;
  121.     time_t    t;
  122.  
  123.     if(argc>1){
  124.         if(!strcmp("?",argv[1]))ShowHelp();
  125.     }
  126.     if(argc==1)
  127.         poet=LoadPoet("poet.txt");
  128.     else
  129.         poet=LoadPoet(argv[1]);
  130.  
  131.     //    Allocate space for strings
  132.     SubStr=(char *)GetMem(MAX_LINE_LENGTH*sizeof(char), "Couldnt allocate space for subject string\n");
  133.     ObjStr=(char *)GetMem(MAX_LINE_LENGTH*sizeof(char), "Couldnt allocate space for object string\n");
  134.  
  135.     //    Randomize timer
  136.     time(&t);
  137.     j=(int)t;
  138.     srand(j);
  139.  
  140.     //    GET OPTIONS
  141.     for(j=2; j<argc; j++){
  142.         ss=argv[j];
  143.         if( (ss[0]=='-') || (ss[0]='/') ){
  144.             switch(ss[1]){
  145.             case 'L': case 'l':
  146.                 NumberLines=StringToBin(&ss[2]);
  147.                 break;
  148.             case 'W': case 'w':
  149.                 PrintWidth=StringToBin(&ss[2]);
  150.                 break;
  151.             case 'S': case 's':
  152.                 seed=StringToBin(&ss[2]);
  153.                 srand(seed);
  154.                 break;
  155.             case '?': case 'H': case 'h':
  156.                 ShowHelp();
  157.                 break;
  158.             default:
  159.                 break;
  160.             }
  161.         }else if(ss[0]=='?'){
  162.             ShowHelp();
  163.         }
  164.     }
  165.         
  166.     if(!poet)ErrorExit("Couldnt load poet data\n");
  167.     poem=(char *)GetMem(64000,"Ran out of memory allocating buffer to recieve poems\n");
  168.     seed=0;
  169.     do{
  170.         ComposePoem(poem, poet, seed);
  171.         printf("\n\n");
  172.         printf(poem);
  173.         printf("\nENTER TO CONTINUE - Q = QUIT\n");
  174.         input=getchar();
  175.         seed++;
  176.     }while( (input!='q') && (input!='Q') );
  177.  
  178.     ErrorExit(0);
  179.     return 1;
  180. }
  181.  
  182. //***********************************************
  183. //    Show programs help screen
  184. //***********************************************
  185. //    Input:        None
  186. //    Output:        None
  187. //***********************************************
  188. void    ShowHelp(void)
  189. {
  190.     printf(    "Random Poetry Generator Copyright 1997 - Paul Gaze\n"
  191.             "Version 1.00   "__DATE__"\n"
  192.             "\n"
  193.             "Syntax: poem <filename> options\n"
  194.             "\n"
  195.             "Options can any of the following:\n"
  196.             "    -Wnn  Set Characters per line to nn (default 60)\n"
  197.             "    -Snn  Set random number seed to nn. Normaly its set\n"
  198.             "          according to the current time\n"
  199.             "    -Lnn  Set lines per poem to nn (default 6)\n"
  200.             "    ?     Show this help screen\n"
  201.             "\n"
  202.             "filename is the name of the file containing the poetry data.\n"
  203.             "If it isnt specified then the program will attempt to load\n"
  204.             "a file called poet.txt\n"
  205.             "\n"
  206.     );
  207.     ErrorExit("");
  208. }
  209.  
  210. //***********************************************
  211. //    Figure out the person of a noun, taking into
  212. //    account if its quality is being used. Also
  213. //    make list of types.
  214. //***********************************************
  215. //    Input:        Thing
  216. //    Output:        None
  217. //***********************************************
  218. void    SetGenda(THING *t)
  219. {
  220.     t->HisGenda=t->Noun->Genda;
  221.     if(t->Quality){
  222.         t->Genda=t->Quality->Genda;
  223.         t->Types=t->Quality->Types;
  224.         t->NTypes=t->Quality->NTypes;
  225.     }else{
  226.         t->Genda=t->Noun->Genda;
  227.         t->Types=t->Noun->Types;
  228.         t->NTypes=t->Noun->NTypes;
  229.     }
  230. }
  231.  
  232. //***********************************************
  233. //    Randomly choose a noun
  234. //***********************************************
  235. //    Input:        Poet data & output for noun
  236. //    Output:        None
  237. //***********************************************
  238. void    NewThing(POET *p, THING *t)
  239. {
  240.     t->N=RND(p->NNoun);
  241.     t->Noun=&p->Noun[t->N];
  242.     t->Quality=0;
  243.     SetGenda(t);
  244. }
  245.  
  246. //***********************************************
  247. //    Randomly choose a quality of a noun
  248. //***********************************************
  249. //    Input:        Poet data & thing to choose a
  250. //                quality of
  251. //    Output:        None
  252. //***********************************************
  253. void    ChooseQuality(POET *p, THING *t)
  254. {
  255.     int        j;
  256.     TYPE    *type;
  257.  
  258.     if(!t->Noun->NTypes){
  259.         ErrorExit("Strangely this noun had no types\n");
  260.         return;
  261.     }
  262.     j=RND(t->Noun->NTypes);
  263.     type=&p->Type[t->Noun->Types[j]];
  264.     if(!type->NQuality){
  265.         return;
  266.     }
  267.     j=RND(type->NQuality);
  268.     t->Quality=&type->Quality[j];
  269.     SetGenda(t);
  270. }
  271. //***********************************************
  272. //    Substitute string
  273. //***********************************************
  274. //    Input:        String to replace, replacement,
  275. //                string to work on
  276. //    Output:        None
  277. //***********************************************
  278. void    Replace(char *key, char *replacement, char *str)
  279. {
  280.     char    *from, *comp, *to;
  281.     int        j, nchar, move;
  282.  
  283.     for(; *str; str++){
  284.         from=str;
  285.         for(comp=key; *comp; comp++,from++){
  286.             if(*comp!=*from)break;
  287.         }
  288.         if(*comp)continue;
  289.  
  290.         //    MAKE SPACE TO PUT IN SUBSTITUTE
  291.         move=strlen(replacement)-strlen(key);
  292.         if(move>0){
  293.             from=str+strlen(str);
  294.             to=from+move;
  295.             nchar=strlen(str)-strlen(key)+1;
  296.             for(j=nchar; j; j--){
  297.                 *to=*from;
  298.                 to--; from--;
  299.             }        
  300.         }else if(move<0){
  301.             from=str+strlen(replacement);
  302.             to=from+move;
  303.             while(*from){
  304.                 *to++=*from++;
  305.             }
  306.             *to++=0;
  307.         }
  308.         memcpy(str, replacement, strlen(replacement) );
  309.     }
  310. }
  311.  
  312.  
  313.  
  314.  
  315. //***********************************************
  316. //    Create a random poem
  317. //***********************************************
  318. //    Input:        output for string, poet data &
  319. //                seed form random number generator
  320. //    Output:        None
  321. //***********************************************
  322. void    ComposePoem(char *output, POET *poet, int seed)
  323. {
  324.     int        verb,UseableVerbs,i,j,k,xx;
  325.     char    *ex,letter;
  326.     VERB    *v;
  327.     THING    sub,obj,temp;
  328.     THING    sub_last,obj_last;
  329.  
  330.     sub.String=SubStr;
  331.     obj.String=ObjStr;
  332.     NewThing(poet, &sub);
  333.     NewThing(poet, &obj);
  334.     sub_last.N=-1;
  335.     sub_last.Quality=0;
  336.     obj_last.N=-1;
  337.     obj_last.Quality=0;
  338.  
  339.     *output=0;
  340.     for(j=0; j<NumberLines; j++){
  341.         do{
  342.             v=poet->Verb;
  343.             UseableVerbs=0;
  344.             for(k=0; k<poet->NVerb; k++,v++){
  345.  
  346. //***********************************************************
  347. #define    CHECK_VERB                                            \
  348.                 for(i=0; i<sub.NTypes; i++){                \
  349.                     if(sub.Types[i]==v->Subject)break;        \
  350.                 }                                            \
  351.                 if(i==sub.NTypes)continue;                    \
  352.                 for(i=0; i<obj.NTypes; i++){                \
  353.                     if(obj.Types[i]==v->Object)break;        \
  354.                 }                                            \
  355.                 if(i==obj.NTypes)continue;
  356. //***********************************************************
  357.                 CHECK_VERB
  358.                 UseableVerbs++;
  359.             }
  360.             if(!UseableVerbs){
  361.                 NewThing(poet, &sub);
  362.                 NewThing(poet, &obj);
  363.             }
  364.         }while(!UseableVerbs);
  365.         verb=RND(UseableVerbs)+1;
  366.         v=poet->Verb;
  367.         for(v=poet->Verb; 1; v++){
  368.             CHECK_VERB
  369.             verb--;
  370.             if(!verb)break;
  371.         }
  372.         if(RND(100)<33){
  373.             ex=poet->Exclamation[RND(poet->NExclamation)];
  374.         }else{
  375.             ex=0;
  376.         }
  377.         
  378.  
  379.         //    GET OBJECT STRING
  380.         if(obj.N==obj_last.N && obj.Quality==obj_last.Quality){
  381.             sprintf( obj.String, Him[obj.Genda]);
  382.         }else{
  383.             if(obj.Quality){
  384.                 sprintf(obj.String, "%s %s",His[obj.HisGenda],obj.Quality->String);
  385.             }else{
  386.                 sprintf(obj.String, obj.Noun->String);
  387.             }
  388.         }
  389.  
  390.         //    GET SUBJECT STRING
  391.         if(sub.N==sub_last.N && sub.Quality==sub_last.Quality){
  392.             sprintf( sub.String, He[sub.Genda]);
  393.         }else{
  394.             if(sub.Quality){
  395.                 sprintf(sub.String, "%s %s",His[sub.HisGenda],sub.Quality->String);
  396.             }else{
  397.                 sprintf(sub.String, sub.Noun->String);
  398.             }
  399.         }
  400.         if(ex){
  401.             sprintf(output,"%s %s,\n", ex, v->String);
  402.         }else{
  403.             sprintf(output,"%s,\n", v->String);
  404.         }
  405.         Replace("*sub", sub.String, output);
  406.         Replace("*psub", His[sub.Genda], output); 
  407.         Replace("*ref", Himself[sub.Genda], output); 
  408.  
  409.         Replace("*obj", obj.String, output);
  410.         Replace("*pobj", His[obj.Genda], output); 
  411.  
  412.         //    MAKE FIRST LETTER CAPITAL
  413.         letter=*output;
  414.         if( (letter>='a') && (letter<='z') )letter+=('A'-'a');
  415.         *output=letter;
  416.         IndentLine(output);        
  417.  
  418.  
  419.         output+=(strlen(output));
  420.  
  421.         sub_last=sub;
  422.         obj_last=obj;
  423.  
  424.         //    CHANGE OBJECT & SUBJECT
  425.         xx=RND(100);
  426.         if(xx<15){
  427.             NewThing(poet, &obj);
  428.         }else if(xx<30){
  429.             NewThing(poet, &sub);
  430.         }else if(xx<45){
  431.             ChooseQuality(poet, &obj);
  432.         }else if(xx<60){
  433.             ChooseQuality(poet, &sub);
  434.         }else if(xx<80){
  435.             temp=sub;
  436.             sub=obj;
  437.             obj=temp;
  438.         }
  439.     }
  440.     output-=2;
  441.     *output='.';
  442. }
  443.  
  444. //***********************************************
  445. //    Return number in range 0 -> limit-1
  446. //***********************************************
  447. //    Input:        Range
  448. //    Output:        Random number
  449. //***********************************************
  450. int    RND(int range)
  451. {
  452.     return    rand()%range;
  453. }
  454.  
  455. //***********************************************
  456. //    Format line to fit in display width
  457. //***********************************************
  458. //    Input:        String for line
  459. //    Output:        None
  460. //***********************************************
  461. void    IndentLine(char *line)
  462. {
  463.     char    *indent="\n    ";
  464.     char    *from,*to;
  465.     int        move,nchar,j;    
  466.  
  467.     while(1){
  468.         nchar=strlen(line);
  469.         if(nchar<PrintWidth)break;
  470.         j=PrintWidth;
  471.         while( line[j]!=' ' ){
  472.             j--;
  473.             if(j<0)return;
  474.         }
  475.         line=&line[j];
  476.         move=strlen(indent)-1;
  477.         nchar=strlen(line)+1-1;
  478.         from=&line[strlen(line)];
  479.         to=&from[move];
  480.         while(nchar){
  481.             *to=*from;
  482.             to--; from--;
  483.             nchar--;
  484.         }
  485.         memcpy(line, indent, strlen(indent));
  486.         line++;
  487.     }
  488. }
  489. //***********************************************
  490. //    Exit code with an error message
  491. //***********************************************
  492. //    Input:        Pointer to error message
  493. //    Output:        None
  494. //***********************************************
  495. void    ErrorExit(char *message)
  496. {
  497.     if(message)printf(message);
  498.  
  499.     //    Free all memory
  500.     while(MemList){
  501.         FreeMem(MemList->Data);
  502.     }
  503.     #if    DEBUG_MESSAGES
  504.         printf("%d bytes left unfreed\n",(int)TotalMemory);
  505.     #endif
  506.     exit(1);
  507. }
  508. //***********************************************
  509. //    Load data for poet from file
  510. //***********************************************
  511. //    Input:    File name
  512. //    Output:    Pointer to poet data
  513. //***********************************************
  514. POET    *LoadPoet(char *name)
  515. {
  516.     char         *data=NULL,*from,*from2,*to,letter,*str,*str2;
  517.     FILE        *f=NULL;
  518.     size_t        length;
  519.     int            nline, blank, j, k, doneit, n, start, end, nletter;
  520.     int            iverb, sub_type, obj_type, finished;
  521.     POET        *p=0;
  522.     char        **line,*ss;
  523.     NOUN        *noun;
  524.     VERB        *v;
  525.     TYPE_DATA    *TypeData=0, *t;
  526.     TYPE        *tt;
  527.  
  528.     //    SET UP INITIAL STRUCTURE
  529.     p=(POET *)GetMem(sizeof(POET),"Couldnt allocate space for poet data\n");
  530.     memset(p, 0, sizeof(POET));
  531.  
  532.     //    LOAD IN DATA
  533.     f=fopen(name,"rb");
  534.     if(f==NULL)FAIL("Unable to open poet file\n");
  535.     if(fseek(f, 0, SEEK_END))FAIL("Trouble reading poet file\n");
  536.     length=ftell(f);
  537.     data=(char *)GetMem(length+1, "Trouble allocating data to read poet file\n");
  538.     if(fseek(f, 0, SEEK_SET))FAIL("Trouble reading poet file\n");;
  539.     if(length!=fread(data, 1, length, f))FAIL("Trouble reading poet file\n");
  540.     data[length]=0;
  541.     fclose(f);
  542.  
  543.     //    REMOVE ESCAPE CHARACTERS
  544.     from=to=data;
  545.     while( (letter=*from++) ){
  546.         if(letter!=0x0d)
  547.             *to++=letter;
  548.     }
  549.     *to++=0;
  550.  
  551.     //    REMOVE COMMENTS & BLANK LINES    
  552.     from=to=data;
  553.     while(1){
  554.         letter=*from;
  555.         if(!letter)break;
  556.         if(letter==';'){
  557.             while(1){
  558.                 letter=*from++;
  559.                 if( (letter=='\n') || (!letter) )break;
  560.             }
  561.         }else{
  562.             blank=1;
  563.             nline=0;
  564.             from2=from;
  565.             while(1){
  566.                 nline++;
  567.                 letter=*from2++;
  568.                 if( (letter=='\n') || (!letter) )break;
  569.                 if( (letter!=' ') && (letter!='    ') ){
  570.                     blank=0;
  571.                 }
  572.             }
  573.             if(!blank){
  574.                 memcpy(to, from, nline);
  575.                 to+=nline;
  576.             }
  577.             from+=nline;
  578.         }
  579.     }
  580.     *to++=0;
  581.  
  582.     //    DIVIDE INTO LINES
  583.     nline=0;
  584.     from=data;
  585.     do{
  586.         letter=*from++;
  587.         if( (!letter) || (letter=='\n') ){
  588.             nline++;
  589.         }
  590.     }while(letter);
  591.     line=(char **)GetMem(nline*sizeof(char *), "Trouble allocating memory for poet file\n");
  592.     from=data;
  593.     for(j=0; j<nline; j++){
  594.         line[j]=from;
  595.         do{
  596.             letter=*from++;
  597.             if( (letter=='\n')||(!letter) )
  598.                 break;
  599.         }while(1);
  600.         from--;
  601.         *from++=0;
  602.     }    
  603.  
  604.     //    GET RID OF GARBAGE AT END OF LINE
  605.     for(j=0; j<nline; j++){
  606.         from=line[j];
  607.         n=strlen(from);
  608.         doneit=0;
  609.         for(;n>=0;n--){
  610.             letter=from[n];
  611.             switch(letter){
  612.             case 0: case '    ':case ' ':
  613.                 from[n]=0;
  614.                 break;
  615.             default:
  616.                 doneit=1;
  617.                 break;
  618.             }
  619.             if(doneit)break;
  620.         }
  621.     }
  622.  
  623.     //////////////////////////////////////
  624.     //                                    //
  625.     //    GET TYPES                        //
  626.     //                                    //
  627.     //////////////////////////////////////
  628.     p->NType=0;
  629.     for(j=0; j<nline; j++){
  630.         str=line[j];
  631.         str=strstr(str,"/");
  632.         if(!str)continue;    
  633.         do{
  634.             str2=strstr(str+1,"/");
  635.             if(!str2)break;
  636.             nletter=((int)str2)-((int)str)+1;
  637.             for(t=TypeData; t; t=(TYPE_DATA *)t->Next){
  638.                 if(nletter!=strlen(t->String))continue;
  639.                 if( !memcmp(str,t->String,nletter) )break;
  640.             }
  641.             if(!t){
  642.                 p->NType++;
  643.                 t=(TYPE_DATA *)GetMem(sizeof(TYPE_DATA), 0);
  644.                 t->Next=TypeData;
  645.                 TypeData=t;
  646.                 t->String=(char *)GetMem(nletter+1, 0);
  647.                 memcpy(t->String, str, nletter);
  648.                 t->String[nletter]=0;
  649.             }
  650.             str=str2;
  651.         }while(1);
  652.     }
  653.     p->Type=(TYPE *)GetMem(p->NType*sizeof(TYPE), 0);
  654.     memset(p->Type, 0, p->NType*sizeof(TYPE));
  655.     t=TypeData;
  656.     for(j=0; j<p->NType; j++){
  657.         p->Type[j].String=t->String;
  658.         t=(TYPE_DATA *)t->Next;
  659.     }
  660.  
  661.     //////////////////////////////////////
  662.     //                                    //
  663.     //    READ EXCLAMATIONS                //
  664.     //                                    //
  665.     //////////////////////////////////////
  666.     start=FindLine(line, nline, "&EXCLAMATIONS");
  667.     if(start==nline)FAIL("Couldnt find &EXCLAMATIONS\n");
  668.  
  669.     end=FindLine(line, nline, "&ENDEXCLAMATIONS");
  670.     if(end==nline)FAIL("Couldnt find &ENDEXCLAMATIONS\n");
  671.     p->NExclamation=end-start-1;
  672.     if(p->NExclamation<=0)FAIL("Dodgy exclamation data\n");
  673.  
  674.     p->Exclamation=(char **)GetMem(p->NExclamation*sizeof(char *), "Trouble allocating memory for exclamation data\n");
  675.     for(j=0; j<p->NExclamation; j++){
  676.         from=line[start+j+1];
  677.         p->Exclamation[j]=(char *)GetMem(strlen(from) + 1, "Couldnt allocate memory for exclamation data\n");
  678.         strcpy(p->Exclamation[j], from);
  679.     }
  680.  
  681.     //////////////////////////////////////
  682.     //                                    //
  683.     //    GET NOUNS                        //
  684.     //                                    //
  685.     //////////////////////////////////////
  686.     start=FindLine(line, nline, "&NOUNS");
  687.     if(start==nline)FAIL("Couldnt find &NOUNS\n");
  688.     end=FindLine(line, nline, "&ENDNOUNS");
  689.     if(end==nline)FAIL("Couldnt find &ENDNOUNS\n");
  690.     p->NNoun=end-start-1;
  691.     if(p->NNoun<=0)FAIL("No nouns found\n");
  692.  
  693.     noun=p->Noun=(NOUN *)GetMem(p->NNoun*sizeof(NOUN), "Ran out of memory\n");
  694.     for(j=0; j<p->NNoun; j++, noun++){
  695.         from=line[start+j+1];
  696.         ReadNoun(from, noun, p);
  697.  
  698.     }
  699.  
  700.     //////////////////////////////////////
  701.     //                                    //
  702.     //    GET VERBS                        //
  703.     //                                    //
  704.     //////////////////////////////////////
  705.     start=FindLine(line, nline, "&VERBS");
  706.     if(start==nline)FAIL("Couldnt find &VERBS\n");
  707.     end=FindLine(line, nline, "&ENDVERBS");
  708.     if(end==nline)FAIL("Couldnt find &ENDVERBS\n");
  709.  
  710.     //    COUNT VERBS & ALLOCATE SPACE FOR THEM
  711.     p->NVerb=0;
  712.     for(j=start+1; j<end; j++){
  713.         if(!strstr(line[j],"/")){
  714.             p->NVerb++;
  715.         }
  716.     }
  717.     if(!p->NVerb)FAIL("There arent any verbs\n");
  718.     v=p->Verb=(VERB *)GetMem(p->NVerb*sizeof(VERB), "Ran out of space allocating memory for verbs\n");
  719.     j=start+1;
  720.     iverb=0;
  721.     finished=0;
  722.     while(!finished){
  723.         if(!strstr(line[j],"/"))FAIL("corrupt verb data 1\n");
  724.         sub_type=obj_type=-1;
  725.         for(k=0; k<p->NType; k++){
  726.             str=strstr(line[j],p->Type[k].String);
  727.             if(!str)continue;
  728.             if(str==line[j])sub_type=k;
  729.             ss=line[j]+1;
  730.             str=strstr(line[j],p->Type[k].String);
  731.             if(str)obj_type=k;
  732.         }
  733.         if( (sub_type==-1)||(obj_type==-1) ){
  734.             if(sub_type!=-1)printf("Subject = %s\n",p->Type[sub_type].String);
  735.             if(obj_type!=-1)printf("Object = %s\n",p->Type[obj_type].String);
  736.             FAIL("Corrupt verb data 2\n");
  737.         }
  738.         j++;
  739.         while(!strstr(line[j],"/")){
  740.             v->String=CloneString(line[j]);
  741.             v->Subject=sub_type;
  742.             v->Object=obj_type;
  743.             v++;
  744.             iverb++;
  745.             if(iverb==p->NVerb){
  746.                 finished=1;
  747.                 break;
  748.             }
  749.             j++;
  750.         }
  751.     }
  752.     //    MAKE SURE ALL VERBS HAVE SUBJECT & OBJECT
  753.     v=p->Verb;
  754.     for(j=0; j<p->NVerb; j++,v++){
  755.         k=0;
  756.         if(!strstr(v->String,"*sub"))k+=5;
  757.         if(!strstr(v->String,"*obj"))k+=5;
  758.         if(k){
  759.             to=(char *)GetMem(strlen(v->String)+k+1,"Low memory\n");
  760.             *to=0;
  761.             if(!strstr(v->String,"*sub"))
  762.                 strcat(to,"*sub ");
  763.             strcat(to, v->String);
  764.             if(!strstr(v->String,"*obj"))
  765.                 strcat(to," *obj");
  766.             FreeMem(v->String);
  767.             v->String=to;
  768.         }
  769.     }    
  770.  
  771.     //////////////////////////////////////
  772.     //                                    //
  773.     //    GET QUALITIES                    //
  774.     //                                    //
  775.     //////////////////////////////////////
  776.     start=FindLine(line, nline, "&QUALITIES");
  777.     if(start==nline)FAIL("Couldnt find &QUALITIES\n");
  778.     end=FindLine(line, nline, "&ENDQUALITIES");
  779.     if(end==nline)FAIL("Couldnt find &ENDQUALITIES\n");
  780.     j=start+1;
  781.     while(j<end){
  782.         if( strstr(line[j],"(") )FAIL("Corrupt quality data\n");
  783.         for(k=0; k<p->NType; k++){
  784.             if(!strcmp(p->Type[k].String,line[j]))break;
  785.         }
  786.         if(k==p->NType)FAIL("Failed to find type\n");
  787.         tt=&p->Type[k];
  788.  
  789.         //    COUNT NUMBER OF QUALITIES
  790.         tt->NQuality=0;
  791.         k=j+1;
  792.         while(strstr(line[k],"(")){
  793.             tt->NQuality++;
  794.             k++;
  795.             if(k==end)break;
  796.         }
  797.         noun=tt->Quality=(NOUN *)GetMem(tt->NQuality*sizeof(NOUN), 0);
  798.         for(k=0; k<tt->NQuality; k++){
  799.             ReadNoun(line[k+j+1], noun, p);
  800.             noun++;
  801.         }
  802.         j+=(tt->NQuality+1);
  803.     }
  804.  
  805.     return p;
  806. fail:
  807.     ErrorExit("Couldnt load poet\n");
  808.     return 0;
  809. }
  810.  
  811. //***********************************************
  812. //    Make a copy of a string
  813. //***********************************************
  814. //    Input:        String to copy
  815. //    Output:        Copy of string
  816. //***********************************************
  817. char    *CloneString(char *from)
  818. {
  819.     char *to;
  820.  
  821.     to=(char *)GetMem(strlen(from)+1, 0);
  822.     strcpy(to, from);
  823.     return to;
  824. }
  825.  
  826.  
  827. //***********************************************
  828. //    Find line equal to given string
  829. //***********************************************
  830. //    Input:        list of lines, number of lines &
  831. //                string to be searched for.
  832. //    Output:        number of line on which string is 
  833. //                to be found or nlines if it isnt
  834. //                found.
  835. //***********************************************
  836. int    FindLine(char **lines, int nlines, char *str)
  837. {
  838.     int    j;
  839.  
  840.     for(j=0; j<nlines; j++){
  841.         if(!strcmp(str, lines[j]))break;
  842.     }
  843.     return j;
  844. }
  845.  
  846. //***********************************************
  847. //    Allocate memory    
  848. //***********************************************
  849. //    Input:        Amount to allocate & message to
  850. //                print if allocation fails
  851. //    Output:        pointer to memory allocated
  852. //***********************************************
  853. void    *GetMem(size_t amount, char *ErrorMessage)
  854. {
  855.     void         *data=NULL;
  856.     MEMBLOCK    *mb=NULL;
  857.  
  858.     data=malloc(amount);
  859.     if(data==NULL)goto fail;
  860.     mb=(MEMBLOCK *)malloc(sizeof(MEMBLOCK));
  861.     if(mb==NULL)goto fail;
  862.     mb->Data=data;
  863.     mb->Amount=amount;
  864.     mb->Next=MemList;
  865.     MemList=mb;
  866.     TotalMemory+=amount;    
  867.     return data;
  868. fail:
  869.     if(data!=NULL)free(data);
  870.     if(mb!=NULL)free(mb);
  871.     if(ErrorMessage)printf(ErrorMessage);
  872.     printf("Couldnt allocate %d bytes\n",(int)amount);
  873.     ErrorExit("Ran out of memory\n");
  874. }
  875.  
  876. //***********************************************
  877. //    Free memory
  878. //***********************************************
  879. //    Input:        Pointer to memory to free
  880. //    Output:        None
  881. //***********************************************
  882. void    FreeMem(void *data)
  883. {
  884.     MEMBLOCK    *m,*last;
  885.  
  886.     m=MemList;
  887.     if(m->Data==data){
  888.         MemList=(MEMBLOCK *)m->Next;
  889.     }else{
  890.         last=m;
  891.         m=(MEMBLOCK *)m->Next;
  892.         while(m){
  893.             if(m->Data==data)break;
  894.             last=m;
  895.             m=(MEMBLOCK *)m->Next;
  896.         }
  897.         if(!m)ErrorExit("Tried to free non existant memory block\n");
  898.         last->Next=m->Next;
  899.     }
  900.     TotalMemory-=m->Amount;
  901.     free(m->Data);
  902.     free(m);
  903. }
  904.  
  905. //***********************************************
  906. //    Read data for noun out of string
  907. //***********************************************
  908. //    Input:        Data, output for noun & poet data
  909. //    Output:        None
  910. //***********************************************
  911. void    ReadNoun(char *from, NOUN *noun, POET *p)
  912. {
  913.     char    *str;
  914.     int        nletter, n, k;
  915.  
  916.     //    GET GENDA
  917.     if( strstr(from,"(he)") ){
  918.         noun->Genda=GENDA_HE;            
  919.     }else if( strstr(from,"(she)") ){
  920.         noun->Genda=GENDA_SHE;            
  921.     }else if( strstr(from,"(it)") ){
  922.         noun->Genda=GENDA_IT;            
  923.     }else if( strstr(from,"(they)") ){
  924.         noun->Genda=GENDA_THEY;            
  925.     }else if( strstr(from,"(i)") ){
  926.         noun->Genda=GENDA_I;            
  927.     }else if( strstr(from,"(we)") ){
  928.         noun->Genda=GENDA_WE;            
  929.     }else{
  930.         printf("Trouble on line:\n%s\n",from);
  931.         FAIL("Couldnt find genda of noun\n");
  932.     }
  933.  
  934.     //    GET STRING
  935.     str=from;
  936.     nletter=0;
  937.     while(*str){
  938.         if(*str=='(')break;
  939.         str++;
  940.         nletter++;
  941.     }
  942.     if(!*str)FAIL("Couldnt get noun string\n");
  943.     noun->String=(char *)GetMem(nletter+1, 0);
  944.     noun->String[nletter]=0;
  945.     memcpy(noun->String, from, nletter);
  946.  
  947.     //    COUNT TYPES & ALLOCATE SPACE FOR THEM
  948.     str=from;
  949.     noun->NTypes=0;
  950.     while(*str){
  951.         if(*str=='/')noun->NTypes++;
  952.         str++;
  953.     }
  954.     noun->NTypes--;
  955.     if(!noun->NTypes)FAIL("No types found for verb\b");
  956.     noun->Types=(int *)GetMem(noun->NTypes*sizeof(int), 0);
  957.  
  958.     //    SET TYPES ARRAY
  959.     str=from;
  960.     k=0;
  961.     for(n=0; n<p->NType; n++){
  962.         if(strstr(from, p->Type[n].String)){
  963.             if(k==noun->NTypes)FAIL("Something went wrong\n");
  964.             noun->Types[k]=n;
  965.             k++;
  966.         }
  967.     }
  968.  
  969.     for(n=0; n<noun->NTypes; n++){
  970.         k=noun->Types[n];
  971.     }
  972.     return;
  973. fail:
  974.     ErrorExit("It went wrong\n");
  975. }
  976.  
  977. //***********************************************
  978. //    Convert ASCII string to integer value
  979. //***********************************************
  980. //    Input:        String
  981. //    Output:        Value
  982. //***********************************************
  983. int    StringToBin(char *str)
  984. {
  985.     int    sum=0,letter;
  986.  
  987.     while( (letter=*str++) ){
  988.         letter-='0';
  989.         if( (letter<0)||(letter>9) )break;
  990.         sum=(sum*10)+letter;
  991.     }
  992.     return sum;
  993. }
  994.